<?php

class Users extends Controller implements IExceptionHandler {

    public function ExceptionHandler(Exception $e) {
        $this->error = $e;
        $this->view('main/index');
    }

    public function GET_index(){
                $this->view('main/users/index');
    }
    
    public function POST_create() {
        /*
         * account
         */
        $PARAM_id_client_account = lib_check_param_post($_POST['client_account_creation']);

        /*
         * login / password
         */
        global $CHECK_LOGIN, $CHECK_PWD_CREATION;
        global $MESSAGE_0016;

        $PARAM_user_login = lib_check_param_post($_POST['login_creation'], $CHECK_LOGIN);
        $PARAM_user_pwd = lib_check_param_post($_POST['pwd_creation'], $CHECK_PWD_CREATION);
        $PARAM_user_pwd_bis = lib_check_param_post($_POST['pwd_creation_bis'], $CHECK_PWD_CREATION);

        if (strcmp($PARAM_user_pwd, $PARAM_user_pwd_bis) != 0) {
            throw new Exception($MESSAGE_0016);
        }

        $tab_arg_1 = [
            ':id_client_account' => $PARAM_id_client_account,
            ':login' => $PARAM_user_login,
            ':pwd' => $PARAM_user_pwd
        ];

        /*
         * user
         */
        global $CHECK_EMAIL, $CHECK_DATE;

        $PARAM_user_name = lib_check_param_post($_POST['user_name_creation']);
        $PARAM_user_firstname = lib_check_param_post($_POST['user_firstname_creation']);
        $PARAM_user_spousename = lib_check_param_post($_POST['user_spousename_creation']);
        $PARAM_user_email = lib_check_param_post($_POST['user_email_creation'], $CHECK_EMAIL);
        $PARAM_user_matricule = lib_check_param_post($_POST['user_matricule_creation']);
        $PARAM_user_function = lib_check_param_post($_POST['user_function_creation']);
        $PARAM_user_profile = lib_check_param_post($_POST['user_profile_creation']);
        $PARAM_user_node = lib_check_param_post($_POST['user_node_creation']);
        $PARAM_user_date_start_contract = lib_change_date_gui_to_mysql(lib_check_param_post($_POST['user_date_start_contract_creation'], $CHECK_DATE));
        $PARAM_user_date_end_contract = lib_change_date_gui_to_mysql(lib_check_param_post($_POST['user_date_end_contract_creation'], $CHECK_DATE));
        $PARAM_id_manager = lib_check_param_post(isset($_POST['user_manager_name_creation']) ? $_POST['user_manager_name_creation'] : NULL);

        $tab_arg_2 = [
            ':user_name' => $PARAM_user_name,
            ':user_firstname' => $PARAM_user_firstname,
            ':user_spousename' => $PARAM_user_spousename,
            ':user_email' => $PARAM_user_email,
            ':user_matricule' => $PARAM_user_matricule,
            ':user_function' => $PARAM_user_function,
            ':user_profile' => $PARAM_user_profile,
            ':user_node' => $PARAM_user_node,
            ':user_date_start_contract' => $PARAM_user_date_start_contract,
            ':user_date_end_contract' => $PARAM_user_date_end_contract,
            ':user_manager_name' => $PARAM_id_manager
        ];

        User::db_create($tab_arg_1, $tab_arg_2);
        $this->view('main/index');
    }

    public function POST_update() {
        global $CHECK_EMAIL, $CHECK_DATE, $CHECK_LOGIN, $CHECK_PWD_CREATION,
        $MESSAGE_0016;

        $PARAM_id_client_account = lib_check_param_post($_POST['client_account_update']);
        $PARAM_id_user = lib_check_param_post($_POST['user_name_update']);
        $PARAM_user_firstname = lib_check_param_post($_POST['user_firstname_update']);
        $PARAM_user_spousename = lib_check_param_post($_POST['user_spousename_update']);
        $PARAM_user_email = lib_check_param_post($_POST['user_email_update'], $CHECK_EMAIL);
        $PARAM_user_matricule = lib_check_param_post($_POST['user_matricule_update']);
        $PARAM_user_function = lib_check_param_post($_POST['user_function_update']);
        $PARAM_user_profile = lib_check_param_post($_POST['user_profile_update']);
        $PARAM_user_node = lib_check_param_post($_POST['user_node_update']);
        $PARAM_user_date_start_contract = lib_change_date_gui_to_mysql(lib_check_param_post($_POST['user_date_start_contract_update'], $CHECK_DATE));
        $PARAM_user_date_end_contract = lib_change_date_gui_to_mysql(lib_check_param_post($_POST['user_date_end_contract_update'], $CHECK_DATE));
        $PARAM_user_login = lib_check_param_post($_POST['login_update'], $CHECK_LOGIN);
        $PARAM_user_pwd = lib_check_param_post($_POST['pwd_update'], $CHECK_PWD_CREATION);
        $PARAM_user_pwd_bis = lib_check_param_post($_POST['pwd_update_bis'], $CHECK_PWD_CREATION);
        $PARAM_id_manager = lib_check_param_post(isset($_POST['user_manager_name_update']) ? $_POST['user_manager_name_update'] : NULL);

        if (strcmp($PARAM_user_pwd, $PARAM_user_pwd_bis) != 0) {
            throw new Exception($MESSAGE_0016);
        }

        $tab_arg_1 = array(':id_user' => $PARAM_id_user,
            ':login' => $PARAM_user_login,
            ':pwd' => $PARAM_user_pwd
        );

        $tab_arg_2 = array(':id_user' => $PARAM_id_user,
            ':user_firstname' => $PARAM_user_firstname,
            ':user_spousename' => $PARAM_user_spousename,
            ':user_email' => $PARAM_user_email,
            ':user_matricule' => $PARAM_user_matricule,
            ':user_function' => $PARAM_user_function,
            ':user_profile' => $PARAM_user_profile,
            ':user_node' => $PARAM_user_node,
            ':user_date_start_contract' => $PARAM_user_date_start_contract,
            ':user_date_end_contract' => $PARAM_user_date_end_contract,
            ':user_id_manager' => $PARAM_id_manager
        );

        $this->user->update_user($PARAM_id_client_account, $tab_arg_1, $tab_arg_2);
        $this->view('main/index');
    }

    public function POST_delete() {
        global $MESSAGE_0045;

//=============================================================================================================
//Attention partie à mettre à jour en fonction des modules rajoutés à l'application où les données utilisateurs
        $PARAM_id_client_account = lib_check_param_post($_POST['client_account_del']);
        $PARAM_id_user = lib_check_param_post($_POST['id_user_del']);

        if ($PARAM_id_user == $this->user->get_id_user()) {
            throw new Exception($MESSAGE_0045);
        }

//=============================================================================================================
// Suppression des EAI du user si compte client possède l'option eai
        if ($this->user->obj_Account->get_eai_status() == 1) {
//==========================================================================
//L'objet EAI est distinct à l'objet USER (pour l'instant) car un user n'a pas forcément 
//d'evaluation car son entreprise n'est pas forcément client de ce module
//            if (!isset($_SESSION['eai'])) { //s'il n'a pas encore été créé
//                $obj_EAI = new EAI($PARAM_id_user, $PARAM_id_client_account, $this->user->obj_Account->get_db_name($PARAM_id_client_account), $this->user->get_id_profile_type($PARAM_id_user, $this->user->obj_Account->get_db_name($PARAM_id_client_account)));
//                $_SESSION['eai'] = $obj_EAI;
//            } else {
//                $obj_EAI = $_SESSION['eai'];
//            }
//
//            $obj_EAI->delete_user_eai($PARAM_id_user);
//
//            $obj_EAI = NULL; //remise à NULL pour forcer la recréation de l'objet car il peut ne pas cibler le bon user (super adm particularité)
            $_SESSION['eai'] = NULL;
        }

//=============================================================================================================
// Suppression des données du user
        $this->user->delete_user($PARAM_id_user, $PARAM_id_client_account);
        $this->view('main/index');
    }

    public function POST_export() {
        /*
         * Compte client spécifié.
         */
        $account_id = $_POST['client_account_id'];

        /*
         * Obtient le nom de la base de données cible
         * à partir de l'identifiant du compte client.
         */
        global $REQUEST_009;
        $db_name = db_request_select($REQUEST_009, [':param_id_compte_client' => $account_id])[0][0];

        /*
         * Obtient tous les utilisateurs
         * pour le compte client spécifié.
         */
        $data = db_request_select(Queries::REQUEST_061, NULL, $db_name, NULL, PDO::FETCH_NUM);

        header('Content-Type: text/csv; charset=' . DEFAULT_ENCODING);
        header('Content-Disposition: attachment; filename="export.csv"');

        $out = fopen('php://output', 'w');
        fputcsv($out, $this->header());
        foreach ($data as $row)
            fputcsv($out, $row);
        fclose($out);
    }

    public function POST_bulk() {
        if (!isset($_FILES['fileToImport']))
            throw new Exception(Strings::MESSAGE_0032);

        /*
         * Compte client spécifié.
         */
        $account_id = $_POST['client_account_creation'];

        /*
         * Obtient le nom de la base de données cible
         * à partir de l'identifiant du compte client.
         */
        global $REQUEST_009;
        $db_name = db_request_select($REQUEST_009, [':param_id_compte_client' => $account_id])[0][0];

        /*
         * Parcours le fichier CSV posté
         * et applique la fonction spécifiée
         * pour chaque ligne du fichier.
         * Les listes des profils et services
         * sont passées en paramètre.
         */
        $data = $this->csv_map($_FILES['fileToImport']['tmp_name'], [$this, 'add_user'], [
            'profiles' => $this->user->get_list_profile($db_name),
            'nodes' => $this->user->get_list_node($db_name),
            'db_name' => $db_name,
            'account_id' => $account_id,
        ]);

        if (!$data)
            throw new Exception(Strings::MESSAGE_0037);

        $this->view('main/index', $data);
    }

    const FIELD_NAME = 'Nom';
    const FIELD_SPOUSENAME = 'Nom d\'épouse';
    const FIELD_FIRSTNAME = 'Prénom';
    const FIELD_REFERENCE = 'Matricule';
    const FIELD_EMAIL = 'Courriel';
    const FIELD_POSITION = 'Fonction';
    const FIELD_NODE = 'Service';
    const FIELD_HIRE = 'Date d\'entrée';
    const FIELD_TERMINATION = 'Date de sortie';
    const FIELD_LOGIN = 'Identifiant';
    const FIELD_PASSWORD = 'Mot de passe';
    const FIELD_PROFILE = 'Profil';
    const FIELD_MANAGER = 'Manager';

    private function add_user($row, $parameter) {
        /*
         * Exceptions:
         *      ArgumentException : 
         *          The field value is invalid,
         *      ArgumentNullException : 
         *          The field value is required but null,
         *      ArgumentOutOfRangeException : 
         *          The field value is outside the allowable range of values,
         *      ArgumentFormatException :   
         *          The field value format is invalid.
         */

        /*
         * trim empty strings to null
         */
        foreach ($row as $field => $value)
            if (empty(trim($value)))
                $row[$field] = NULL;
        /*
         * validate fields
         */
        if (!$row[self::FIELD_NAME])
            throw new ArgumentNullException(self::FIELD_NAME, sprintf(Strings::MESSAGE_0051, self::FIELD_NAME));

        if (!$row[self::FIELD_FIRSTNAME])
            throw new ArgumentNullException(self::FIELD_FIRSTNAME, sprintf(Strings::MESSAGE_0051, self::FIELD_FIRSTNAME));

        if (!$row[self::FIELD_REFERENCE])
            throw new ArgumentNullException(self::FIELD_REFERENCE, sprintf(Strings::MESSAGE_0051, self::FIELD_REFERENCE));

        if (!$row[self::FIELD_EMAIL])
            throw new ArgumentNullException(self::FIELD_EMAIL, sprintf(Strings::MESSAGE_0051, self::FIELD_EMAIL));

        if (!$row[self::FIELD_POSITION])
            throw new ArgumentNullException(self::FIELD_POSITION, sprintf(Strings::MESSAGE_0051, self::FIELD_POSITION));

        if (!$row[self::FIELD_NODE])
            throw new ArgumentNullException(self::FIELD_NODE, sprintf(Strings::MESSAGE_0051, self::FIELD_NODE));
        $row[self::FIELD_NODE] = $this->user->get_node_by_name($row[self::FIELD_NODE], $parameter['nodes'])['id_noeud'];
        if (!$row[self::FIELD_NODE])
            throw new ArgumentException(self::FIELD_NODE, Strings::MESSAGE_0052);

        if (!$row[self::FIELD_HIRE])
            throw new ArgumentNullException(self::FIELD_HIRE, sprintf(Strings::MESSAGE_0051, self::FIELD_HIRE));
        if (!lib_check_date($row[self::FIELD_HIRE]))
            throw new ArgumentFormatException(self::FIELD_HIRE, Strings::MESSAGE_0014);
        $row[self::FIELD_HIRE] = lib_change_date_gui_to_mysql($row[self::FIELD_HIRE]);

        if ($row[self::FIELD_TERMINATION]) {
            if (!lib_check_date($row[self::FIELD_TERMINATION]))
                throw new ArgumentFormatException(self::FIELD_TERMINATION, Strings::MESSAGE_0014);
            $row[self::FIELD_TERMINATION] = lib_change_date_gui_to_mysql($row[self::FIELD_TERMINATION]);
        }

        if (!$row[self::FIELD_LOGIN])
            throw new ArgumentNullException(self::FIELD_LOGIN, sprintf(Strings::MESSAGE_0051, self::FIELD_LOGIN));
        if (!lib_check_login($row[self::FIELD_LOGIN]))
            throw new ArgumentFormatException(self::FIELD_LOGIN, Strings::MESSAGE_0018);

        if (!$row[self::FIELD_PASSWORD])
            throw new ArgumentNullException(self::FIELD_PASSWORD, sprintf(Strings::MESSAGE_0051, self::FIELD_PASSWORD));
        if (!lib_check_password($row[self::FIELD_PASSWORD]))
            throw new ArgumentFormatException(self::FIELD_PASSWORD, Strings::MESSAGE_0017);

        if (!$row[self::FIELD_PROFILE])
            throw new ArgumentNullException(self::FIELD_PROFILE, sprintf(Strings::MESSAGE_0051, self::FIELD_PROFILE));
        $row[self::FIELD_PROFILE] = $this->user->get_profile_by_name($row[self::FIELD_PROFILE], $parameter['profiles'])['id_profil'];
        if (!$row[self::FIELD_PROFILE])
            throw new ArgumentException(self::FIELD_PROFILE, Strings::MESSAGE_0052);

        if ($row[self::FIELD_MANAGER]) {
            $manager = $this->user->get_manager_by_name($row[self::FIELD_MANAGER], $parameter['db_name']);
            if (!$manager)
                throw new ArgumentException(self::FIELD_MANAGER, Strings::MESSAGE_0052);
            if (!in_array($manager['id_profil_type'], [2, 3, 4, 5]))
                throw new ArgumentOutOfRangeException(self::FIELD_MANAGER, Strings::MESSAGE_0047);
            $row[self::FIELD_MANAGER] = $manager['id_user'];
        }

        /*
         * sql parameters
         */
        $tab_arg_connexion = [
            ':id_client_account' => $parameter['account_id'],
            ':login' => $row[self::FIELD_LOGIN],
            ':pwd' => $row[self::FIELD_PASSWORD]
        ];

        $tab_arg_user = [
            ':user_name' => $row[self::FIELD_NAME],
            ':user_spousename' => $row[self::FIELD_SPOUSENAME],
            ':user_firstname' => $row[self::FIELD_FIRSTNAME],
            ':user_matricule' => $row[self::FIELD_REFERENCE],
            ':user_email' => $row[self::FIELD_EMAIL],
            ':user_function' => $row[self::FIELD_POSITION],
            ':user_node' => $row[self::FIELD_NODE],
            ':user_date_start_contract' => $row[self::FIELD_HIRE],
            ':user_date_end_contract' => $row[self::FIELD_TERMINATION],
            ':user_profile' => $row[self::FIELD_PROFILE],
            ':user_manager_name' => $row[self::FIELD_MANAGER]
        ];

        User::db_create($tab_arg_connexion, $tab_arg_user);

        return $row;
    }

    public function POST_reset() {
        global $CHECK_LOGIN, $CHECK_PWD_CREATION, $CHECK_PWD_CREATION;
        global $MESSAGE_0016;

        $PARAM_id_user = lib_check_param_post($_POST['id_user']);
        $PARAM_user_login = lib_check_param_post($_POST['login_visu_update'], $CHECK_LOGIN);
        $PARAM_user_pwd = lib_check_param_post($_POST['pwd_visu_update'], $CHECK_PWD_CREATION);
        $PARAM_user_pwd_bis = lib_check_param_post($_POST['pwd_visu_update_bis'], $CHECK_PWD_CREATION);

        if (strcmp($PARAM_user_pwd, $PARAM_user_pwd_bis) != 0) {
            throw new Exception($MESSAGE_0016);
        }

        $tab_arg_1 = array(':id_user' => $PARAM_id_user,
            ':login' => $PARAM_user_login,
            ':pwd' => $PARAM_user_pwd
        );
        $this->user->update_user(NULL, $tab_arg_1, NULL);
        $this->view('main/index');
    }

    private function header() {
        return [
            self::FIELD_NAME,
            self::FIELD_SPOUSENAME,
            self::FIELD_FIRSTNAME,
            self::FIELD_REFERENCE,
            self::FIELD_EMAIL,
            self::FIELD_POSITION,
            self::FIELD_NODE,
            self::FIELD_HIRE,
            self::FIELD_TERMINATION,
            self::FIELD_LOGIN,
            self::FIELD_PASSWORD,
            self::FIELD_PROFILE,
            self::FIELD_MANAGER,
        ];
    }

    private function validate_header($header) {
        /*
         * Exceptions:
         *      HeaderDataException : 
         *          The header is invalid,
         */

        /*
         * uniqueness
         */
        if (count(array_unique($header)) !== count($header))
            throw new HeaderDataException(Strings::MESSAGE_0050);

        /*
         * existence
         */
        $expected_header = $this->header();

        foreach ($expected_header as $key => $value)
            if (!in_array($value, $header))
                throw new HeaderDataException(sprintf(Strings::MESSAGE_0049, $value));

        return $header;
    }

    private function csv_map($filename, callable $callback, $parameter = NULL, $delimiter = ',') {
        if (!file_exists($filename) || !is_readable($filename))
            return FALSE;

        $header = NULL;
        $data = [];
        $rowcount = 1;
        if (($handle = fopen($filename, 'r')) !== FALSE) {
            try {
                while (($row = fgetcsv($handle, /* maximum line length: */ 1000, $delimiter)) !== FALSE) {
                    if (!$header) {
                        $header = $this->validate_header($row);
                    } else {
                        ++$rowcount;
                        try {
                            if (count($header) !== count($row))
                                $data[] = ['exception' => new RowLengthException($rowcount, Strings::MESSAGE_0055)];
                            else {
                                $associative_array = array_combine($header, $row);
                                $data[] = [/* 'exception' => NULL,  */'row' => call_user_func($callback, $associative_array, $parameter)];
                            }
                        } catch (ArgumentException $e) {
                            $data[] = ['exception' => new RowDataException($rowcount, NULL, NULL, $e)/* , 'row' => $associative_array */];
                        } catch (SqlCommandException $e) {
                            $data[] = ['exception' => new RowDataException($rowcount, $e->getMessage())/* , 'row' => $associative_array */];
                        }
                    }
                }
            } catch (HeaderDataException $e) {
                throw $e;
            } finally {
                fclose($handle);
            }
            return $data;
        }
        return FALSE;
    }

}
